"""
装饰器 - 给被装饰的函数或类增加额外的能力
横切关注功能：跟正常的业务逻辑没有必然联系且可以动态添加和移除的功能
横切关注功能应该从正常的业务代码中剥离，通过代理的方式动态植入
    ~ 代理模式（有代理对象执行被代理对象的行为并增加额外的功能）
    ~ 调用函数之前的检查工作（例如：参数类型检查）
    ~ 提供缓存服务
    ~ 上下文服务（锁服务、容器服务）
"""
import random
import time

from functools import wraps

import pymysql


class RecordTime:

    def __init__(self, make_log):
        self.make_log = make_log
    
    def __call__(self, func):

        @wraps(func)
        def wrapper(*args, **kwargs):
            start = time.time()
            result = func(*args, **kwargs)
            end = time.time()
            self.make_log(func.__name__, end - start)
            return result
        
        return wrapper



# 带参数的装饰器要先通过函数传入装饰器参数该函数返回装饰器函数
def record_time(make_log):

    # 装饰器函数的参数是被装饰的函数或类
    def decorator(func):

        @wraps(func)
        def wrapper(*args, **kwargs):
            # 在调用被装饰的函数之前添加额外的功能
            start = time.time()
            # 调用被装饰的函数并获取返回值
            result = func(*args, **kwargs)
            # 在调用被装饰的函数之后添加额外的功能
            end = time.time()
            make_log(func.__name__, end - start)
            return result

        # 装饰器函数的返回值是带装饰功能的函数
        return wrapper
    
    # 返回装饰器函数
    return decorator


def output(name, duration):
    print(f'{name}函数执行时间: {duration}秒')


def write_to_db(name, duration):
    conn = pymysql.connect(host='120.77.222.217', port=3306,
                           user='root', password='123456',
                           database='demo', charset='utf8',
                           autocommit=True)
    try:
        with conn.cursor() as cursor:
            cursor.execute(
                'insert into tb_func_log values (default, %s, %s)',
                (name, round(duration, 3))
            )
    except:
        pass
    finally:
        conn.close()


@record_time(write_to_db)
def download(file):
    print(f'开始下载{file}...')
    time.sleep(random.randint(1, 10))
    print(f'{file}下载完成...')


def write_to_file(name, duration):
    with open('my.log', 'a') as file:
        file.write(f'{name}函数执行时间: {duration}秒\r\n')


@RecordTime(write_to_file)
def upload(file):
    print(f'开始上传{file}...')
    time.sleep(random.randint(5, 10))
    print(f'{file}上传完成...')


# decorated_upload = record_time(upload)
# print(download.__name__)
# download('Python从入门到住院.avi')
# print(upload.__name__)
# upload('MySQL从删库到跑路.pdf')
# 取消装饰器
# upload.__wrapped__('MySQL从删库到跑路.pdf')
# decorated_upload('MySQL从删库到跑路.pdf')


def truncate_string(max_len):

    def decorator(func):
        
        @wraps(func)
        def wrapper(*args, **kwargs):
            result = func(*args, **kwargs)
            if isinstance(result, str) and len(result) > max_len:
                result = result[:max_len] + '...'
            return result
        
        return wrapper

    return decorator


def title_string(func):

    @wraps(func)
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        if isinstance(result, str):
            result = result.title()
        return result
    
    return wrapper


@title_string
@truncate_string(10)
def say_hello():
    return 'hello, world!'


# print(say_hello())
